const fs = require("fs");
const path = require("path");
const http = require("http");
const https = require("https");
const url = require("url");
const FormData = require("form-data");
const buffer = require("buffer");
const axios = require("axios").default;
const randomstring = require("randomstring");
const rannum = require("random-number");
const rp = require("request-promise-native");
const B64 = require("b64");
const base64 = require("js-base64");
base64.Base64.extendString();
const stream = require("stream");
const util = require("util");
const CombinedStream = require("combined-stream");
const String2Stream = require("string-to-stream");
const getStream = require("get-stream");
const MD5 = require("md5");
const qs = require("querystring");
const get_token = require("./get-token");


const upload_url = "http://upload.qiniu.com/";
const parsed = url.parse(upload_url);





/**
 * 
 * @param {String} full_path 
 * @returns {Promise<{ok:boolean,msg:String,url:String}>}
 */
function uploadSingle(full_path) {
  return new Promise(async (resolve) => {
    let file_stream = fs.createReadStream(full_path);
    let ext_name = path.extname(full_path);
    ext_name = ext_name ? ext_name.replace(".", "") : "bin";

    let o_getToken = await get_token.getUploadToken(ext_name);
    if (!o_getToken.ok) {
      return resolve({
        ok: false,
        msg: `Error then trying get upload token : ${o_getToken.msg}`,
        url: ""
      })
    }
    let token = o_getToken.token;
    let remote_filename = o_getToken.remote_filename;

    let form = new FormData;
    form.append("file", file_stream, {
      filename: `${randomstring.generate(5)}.${ext_name}`
    });
    form.append("key", remote_filename);
    form.append("token", token);
    let headers = {
      "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36",
      "Referer": "http://pianke.me/editor/",
      'X-Requested-With': 'XMLHttpRequest',
    }
    let request = http.request({
      method: "POST",
      host: parsed.host,
      path: parsed.path,
      headers: {
        ...form.getHeaders(),
        ...headers
      }
    });
    form.on("error", err => {
      resolve({
        ok: false,
        msg: `form.on(error):${err.message}`,
        url: ""
      })
    });
    form.pipe(request);
    request.on("response", (resp) => {
      let buf = new buffer.Buffer("");
      resp.on("data", chunk => {
        buf += chunk;
      })
      resp.on("end", $ => {
        try {
          let obj = JSON.parse(buf);
          let file_url = `https://qnimg.pianke.me/${obj['key']}`;
          // console.log(path.basename(full_path));
          // console.log(file_url);
          resolve({
            ok: true,
            msg: "ok",
            url: file_url
          })
        } catch (err) {
          resolve({
            ok: false,
            msg: `error when try get url from response :${err.message}`,
            url: ""
          })
        }
      })      // resp.pipe(process.stdout);
    });
    request.on("error", err => {
      resolve({
        ok: false,
        msg: `request.on(error):${err.message}`,
        url: ""
      })
    });
  })
}
/**
 * @param {Number} x
 * @param {String} full_path 
 * @returns {Promise<{url:String,ok:Boolean,msg:String[]}>}
 */
function uploadSingleForXTime(x, full_path) {
  let g = (function* () {
    for (let i = 1; i <= x; i++) {
      yield uploadSingle(full_path);
    }
  })();
  let it = g.next();
  let error_messages = [];
  return new Promise((resolve, reject) => {
    (function bootstrap() {
      if (it.done) {
        resolve({
          ok: false,
          msg: error_messages,
          url: ""
        })
      } else {
        it.value.then((o) => {
          if (o.ok) {
            resolve({
              ok: true,
              msg: ["ok"],
              url: o.url
            })
          } else {
            it = g.next();
            error_messages.push(o.msg);
            setTimeout($ => bootstrap(), 2000)
          }
        })
      }
    })();
  })
}




if (!module.parent) {
  uploadSingle(path.join(__dirname, "./index.js"));
}

module.exports = {
  uploadSingleForXTime: uploadSingleForXTime,
  uploadSingle
}